#include "simplemodewidget.h"
#include "../../src/common/utils/utils.h"

#include <DDialog>

#include <QVBoxLayout>

SimpleModeWidget::SimpleModeWidget(ProcCleanerModel *model, QWidget *parent)
    : QWidget(parent)
    , m_model(model)
    , m_appListViewModel(nullptr)
    , m_appListView(nullptr)
    , m_totalMemoryUsageLabel(nullptr)
    , m_cleanBtn(nullptr)
{
    initUI();
    initData();
    initConnections();
    postInit();
}

SimpleModeWidget::~SimpleModeWidget()
{
}

void SimpleModeWidget::updateProcInfo()
{
    ProcInfoList procInfoList = m_model->getProcInfoList();

    // 整理成应用信息映射表
    QMap<QString, AppInfo> pkgNameToAppInfoMap;
    for (ProcInfoList::const_iterator cIter = procInfoList.begin();
         cIter != procInfoList.end(); cIter++) {
        // 不考虑未知进程
        if (0 == cIter->nPid) {
            continue;
        }
        // 不考虑无包名的进程
        if (cIter->sPkgName.isEmpty()) {
            continue;
        }
        // 不考虑无启动文件的进程
        if (cIter->sDesktopPath.isEmpty()) {
            continue;
        }
        // 隐藏不显示的应用
        if (NeedHideAppPkgNameList.contains(cIter->sPkgName)) {
            continue;
        }

        AppInfo appInfo;
        appInfo.pkgName = cIter->sPkgName;
        appInfo.name = getAppNameFromDesktop(cIter->sDesktopPath);
        if (appInfo.name.isEmpty()) {
            appInfo.name = cIter->sProcName;
        }
        appInfo.icon = cIter->sThemeIcon;
        appInfo.desktopFilePath = cIter->sDesktopPath;
        appInfo.isLocked = m_model->getAppLockState(appInfo.pkgName);

        // 获取进程内存
        AppInfo sameAppInfo = pkgNameToAppInfoMap.value(cIter->sPkgName);
        appInfo.memorySize = sameAppInfo.memorySize
                + m_model->getProcMem(uint(cIter->nPid));
        // 将pid保存到应用的进程pid列表
        appInfo.pids.append(sameAppInfo.pids);
        appInfo.pids.append(uint(cIter->nPid));

        pkgNameToAppInfoMap.insert(cIter->sPkgName, appInfo);
    }

    // 整理出已经退出的应用包名集合
    QList<QString> lastPkgNameList = m_pkgNameToAppInfoMap.keys();
    QSet<QString> lastPkgNameSet = lastPkgNameList.toSet();
    QList<QString> currentPkgNameList = pkgNameToAppInfoMap.keys();
    QSet<QString> currentPkgNameSet = currentPkgNameList.toSet();

    QSet<QString> closedPkgNameSet = lastPkgNameSet - currentPkgNameSet;

    // 整理出新打开的应用包名集合
    QSet<QString> newOpendPkgNameSet = currentPkgNameSet - lastPkgNameSet;

    // 从显示列表中移除已经退出的应用
    for (QSet<QString>::const_iterator cIter = closedPkgNameSet.begin();
         cIter != closedPkgNameSet.end(); cIter++) {
        removeAppViewItem(*cIter);

        // 从正在后台关闭中的app对应的包名列表中移除已关闭的应用包名
        m_pkgNameListOfkillingApp.removeOne(*cIter);
    }

    // 不显示正在后台关闭中的app
    for (QList<QString>::const_iterator cIter = m_pkgNameListOfkillingApp.begin();
         cIter != m_pkgNameListOfkillingApp.end(); cIter++) {
        removeAppViewItem(*cIter);
    }

    for (QMap<QString, AppInfo>::const_iterator cIter = pkgNameToAppInfoMap.begin();
         cIter != pkgNameToAppInfoMap.end(); cIter++) {
        // 不更新已关闭的应用
        if (closedPkgNameSet.contains(cIter.value().pkgName)) {
            continue;
        }
        // 向显示列表中添加新打开的应用
        if (newOpendPkgNameSet.contains(cIter.value().pkgName)) {
            appendAppViewItem(cIter.value());
            continue;
        }

        // 更新显示列表中已经存在的应用
        updateAppViewItem(cIter.value());
    }

    m_pkgNameToAppInfoMap = pkgNameToAppInfoMap;

    // 更新总内存占用
    const ProcCleanerModel::MemInfo &memInfo = m_model->getMemInfo();
    QString totalMemoryUsageStr = QString("%1 / %2").arg(formatBytesByDefault(memInfo.TotalMem - memInfo.AvailableMem))
            .arg(formatBytesByDefault(memInfo.TotalMem));
    m_totalMemoryUsageLabel->setText(totalMemoryUsageStr);
}

void SimpleModeWidget::onItemRequestSetAppLockState(const QString &pkgName, bool lock)
{
    m_model->setAppLockState(pkgName, lock);
    updateProcInfo();
}

void SimpleModeWidget::onItemRequestCloseApp(const AppInfo &info)
{
    // 判断此应用是否禁止强杀
    if (ForbiddenForceKillAppPkgNameList.contains(info.pkgName)) {
        qWarning() << Q_FUNC_INFO << info.pkgName << "forbidden being killed forcedly!";
        DDialog dlg;
        dlg.setIcon(QIcon::fromTheme(info.icon));
        dlg.setMessage(QString("%1(%2) 禁止被强制杀死，请从该程序中手动退出")
                       .arg(info.name).arg(info.pkgName));
        dlg.addButton("确定", true);
        dlg.exec();
        return;
    }

    m_model->asyncKillApps({info});
    m_pkgNameListOfkillingApp.append(info.pkgName);
}

void SimpleModeWidget::onNotifySetAppViewItemVisible(const AppInfo &info, bool visible)
{
    int rowCount = m_appListViewModel->rowCount();
    for (int i = rowCount -1; i >= 0; i--) {
        QModelIndex modeIndex = m_appListViewModel->index(i, 0);
        AppViewItem *appItem = static_cast<AppViewItem *>(m_appListView->indexWidget(modeIndex));
        if (!appItem) {
            continue;
        }

        if (info.pkgName == appItem->getInfo().pkgName) {
            appItem->setVisible(visible);
            break;
        }
    }
}

void SimpleModeWidget::cleanApps()
{
    QList<AppInfo> appsNeedKill;
    for (QMap<QString, AppInfo>::const_iterator cIter = m_pkgNameToAppInfoMap.begin();
         cIter != m_pkgNameToAppInfoMap.end(); cIter++) {
        // 判断此应用是否禁止强杀
        if (ForbiddenForceKillAppPkgNameList.contains(cIter.value().pkgName)) {
            continue;
        }
        // 如果应用加锁，则不清楚
        if (m_model->getAppLockState(cIter.value().pkgName)) {
            continue;
        }

        appsNeedKill.append(cIter.value());
        m_pkgNameListOfkillingApp.append(cIter.value().pkgName);
    }


    m_model->asyncKillApps(appsNeedKill);
}

void SimpleModeWidget::initUI()
{
    setMouseTracking(true);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->setContentsMargins(0, 0, 0, 0);
    mainLayout->setSpacing(0);
    setLayout(mainLayout);

    QHBoxLayout *listViewLayout = new QHBoxLayout;
    listViewLayout->setContentsMargins(0, 0, 0, 0);
    listViewLayout->setSpacing(0);
    mainLayout->addLayout(listViewLayout);

    listViewLayout->addSpacing(30);
    m_appListViewModel = new QStandardItemModel(this);
    m_appListView = new AppListView(this);
    m_appListView->setSpacing(30);
    m_appListView->setViewMode(DListView::ViewMode::IconMode);
    m_appListView->setAutoScroll(false);
    m_appListView->setDragEnabled(false);
    m_appListView->setModel(m_appListViewModel);
    listViewLayout->addWidget(m_appListView, 1);

    // 底部
    QHBoxLayout *bottomLayout = new QHBoxLayout;
    bottomLayout->setContentsMargins(0, 0, 0, 0);
    bottomLayout->setSpacing(0);
    mainLayout->addLayout(bottomLayout);

    // 总内存占用信息
    bottomLayout->addSpacing(20);
    m_totalMemoryUsageLabel = new QLabel(this);
    m_totalMemoryUsageLabel->setText("2.6 G / 13.6 G");
    m_totalMemoryUsageLabel->adjustSize();
    bottomLayout->addWidget(m_totalMemoryUsageLabel, 0, Qt::AlignLeft);

    // 清理按钮
    m_cleanBtn = new QPushButton(this);
    m_cleanBtn->setFlat(true);
    m_cleanBtn->setFixedSize(50, 50);
    m_cleanBtn->setIcon(QIcon::fromTheme("broom"));
    m_cleanBtn->setIconSize(QSize(50, 50));;
    bottomLayout->addWidget(m_cleanBtn, 0, Qt::AlignmentFlag::AlignCenter);

    QWidget *spaceWidget = new QWidget(this);
    spaceWidget->setFixedWidth(m_totalMemoryUsageLabel->width() + 20);
    bottomLayout->addWidget(spaceWidget, 0, Qt::AlignRight);
}

void SimpleModeWidget::initData()
{
}

void SimpleModeWidget::initConnections()
{
    connect(m_model, &ProcCleanerModel::killProcFinished, this, [this]() {
        this->updateProcInfo();
    });
    connect(m_model, &ProcCleanerModel::notifySetUiAppViewItemVisible, this, &SimpleModeWidget::onNotifySetAppViewItemVisible);

    connect(m_cleanBtn, &DIconButton::clicked, this, &SimpleModeWidget::cleanApps);
}

void SimpleModeWidget::postInit()
{
}

void SimpleModeWidget::appendAppViewItem(const AppInfo &info)
{
    AppViewItem *appViewItem = new AppViewItem(info, m_model, this);
    // 当请求关闭应用时
    connect(appViewItem, &AppViewItem::requestCloseApp, this, &SimpleModeWidget::onItemRequestCloseApp);
    QStandardItem *item = new QStandardItem();
    item->setSizeHint(VIEW_ITEM_SIZE);
    m_appListViewModel->appendRow(item);
    int rowCount = m_appListViewModel->rowCount();
    m_appListView->setIndexWidget(m_appListViewModel->index(rowCount - 1, 0), appViewItem);
}

void SimpleModeWidget::removeAppViewItem(const QString &pkgName)
{
    int rowCount = m_appListViewModel->rowCount();
    for (int i = rowCount -1; i >= 0; i--) {
        QModelIndex modeIndex = m_appListViewModel->index(i, 0);
        AppViewItem *appItem = static_cast<AppViewItem *>(m_appListView->indexWidget(modeIndex));
        if (!appItem) {
            continue;
        }

        if (pkgName == appItem->getInfo().pkgName) {
            m_appListViewModel->removeRow(i);
        }
    }
}

void SimpleModeWidget::updateAppViewItem(const AppInfo &info)
{
    int rowCount = m_appListViewModel->rowCount();
    for (int i = rowCount -1; i >= 0; i--) {
        QModelIndex modeIndex = m_appListViewModel->index(i, 0);
        AppViewItem *appItem = static_cast<AppViewItem *>(m_appListView->indexWidget(modeIndex));
        if (!appItem) {
            continue;
        }

        if (info.pkgName == appItem->getInfo().pkgName) {
            appItem->setInfo(info);
        }
    }
}
